#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"

const std::string SEP = "\r\n";
const std::string WebRoot = "./WebRoot";
const std::string defaultPath = "./WebRoot/index.html";
const std::string errorPath = "./WebRoot/err_404.html";
const std::string defaultSuffix = ".html";

// 实用工具包
struct Util
{
    // Http 请求中的结构信息
    struct HttpStruct
    {
        HttpStruct()
        {
        }

        std::string method_;            // 请求的方法
        std::string url_;               // 请求的资源路径
        std::string http_version_;      // Http 的版本
        std::vector<std::string> body_; // 正文数据（有效载荷）

        std::string path_ = WebRoot; // Web 目录
        std::string suffix_;         // 后缀类型
    };

    // 反序列化
    static HttpStruct Deserialize(std::string &msg)
    {
        HttpStruct req; // 反序列化后的结构体

        // 先读取请求行
        std::string requestHeadLine = ReadOneLine(msg);

        // 将第一行中的数据进行格式化
        bool flag = FormatHeadLine(requestHeadLine, &req.method_, &req.url_, &req.http_version_);
        if (!flag)
        {
            logMessage(Error, "FormatHeadLine Faile!");
            return req;
        }

        // 继续读取请求报头
        while (!msg.empty())
        {
            // 继续逐行读取
            std::string line = ReadOneLine(msg);
            req.body_.push_back(line);
        }

        // 读取路径
        req.path_ += req.url_;
        if (req.path_[req.path_.size() - 1] == '/')
            req.path_ = defaultPath; // 默认路径

        // 读取后缀
        int pos = req.url_.rfind(".");
        if (pos != std::string::npos)
            req.suffix_ = req.url_.substr(pos);
        else
            req.suffix_ = defaultSuffix; // 默认文件类型为 HTML

        return req;
    }

    // 读取一行数据
    static std::string ReadOneLine(std::string &msg)
    {
        auto pos = msg.find(SEP);
        if (pos == std::string::npos)
            return "";
        std::string s = msg.substr(0, pos);
        msg.erase(0, pos + SEP.size());

        return s;
    }

    // 格式化首行
    static bool FormatHeadLine(const std::string &requestHeadLine, std::string *pMethod, std::string *pURL, std::string *pVersion)
    {
        // 首行中的数据通过空格链接
        std::stringstream ss(requestHeadLine);
        ss >> *pMethod >> *pURL >> *pVersion;

        // 避免读取错误的情况
        if (*pMethod == "" || *pURL == "" || *pVersion == "")
            return false;

        return true;
    }

    // 读取文件
    static std::string ReadFile()
    {
        // 这里直接指定读取默认页面文件
        struct stat st;
        int n = stat("./WebRoot/index.html", &st);
        if (n < 0)
        {
            logMessage(Error, "Read File Fail!");
            return "";
        }

        int size = st.st_size;

        std::string file;
        file.resize(size);

        int fd = open("./WebRoot/index.html", O_RDONLY);
        if (fd < 0)
        {
            logMessage(Error, "Open File Fail!");
            return "";
        }

        read(fd, (char *)file.c_str(), size);

        return file;
    }

    static std::string ReadFile(const std::string &filePath)
    {
        // 根据传入的路径，读取指定文件
        struct stat st;
        int n = stat(filePath.c_str(), &st);
        if (n < 0)
        {
            logMessage(Error, "Read File Fail!");
            return "";
        }

        int size = st.st_size;

        std::string file;
        file.resize(size);

        int fd = open(filePath.c_str(), O_RDONLY);
        if (fd < 0)
        {
            logMessage(Error, "Open File Fail!");
            return "";
        }

        read(fd, (char *)file.c_str(), size);

        return file;
    }

    // 根据后缀匹配不同的类型
    static std::string GetType(const string &suffix)
    {
        std::string content_type;
        if (suffix == ".html" || suffix == ".htm")
            content_type + "text/html";
        else if (suffix == ".css")
            content_type += "text/css";
        else if (suffix == ".js")
            content_type += "application/x-javascript";
        else if (suffix == ".png")
            content_type += "image/png";
        else if (suffix == ".jpg")
            content_type += "image/jpeg";

        return content_type;
    }

    // 返回是否读取成功
    static bool ReadFile(const std::string &filePath, string &body)
    {
        // 根据传入的路径，读取指定文件
        struct stat st;
        int n = stat(filePath.c_str(), &st);
        if (n < 0)
        {
            logMessage(Error, "Read File Fail!");
            logMessage(Error, "Open File Fail!");

            // 重新打开 404 文件，读取
            n = stat(errorPath.c_str(), &st);
            std::cout << "n: " << n << std::endl; 
            int size = st.st_size;
            body.resize(size);
            std::cout << "size: " << size << std::endl; 
            int fd = open(errorPath.c_str(), O_RDONLY);
            std::cout << "fd: " << fd << std::endl; 
            read(fd, (char *)body.c_str(), size);
            std::cout << "=================" << std::endl;
            std::cout << body << std::endl;
            std::cout << "=================" << std::endl;

            close(fd);
            return false;
        }

        int size = st.st_size;

        body.resize(size);

        int fd = open(filePath.c_str(), O_RDONLY);

        read(fd, (char *)body.c_str(), size);
        
        close(fd);
        return true;
    }
};